﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.IO;
using System.Windows.Media.Imaging;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;

namespace VirtualTileTest2 {
    class TiledImageItem : IVirtualTile {
        private static Size mTileSize;
        private Image mImage;
        private Content mContent;
        private CancellationTokenSource mCts;
        private Object mLock = new Object();

        public static void UpdateTileSize(Size size) {
            mTileSize = new Size(size.Width, size.Height);
        }

        public TiledImageItem(Content content) {
            mContent = content;
        }

        public UIElement Visual {
            get {
                return mImage;
            }
        }

        /// <summary>
        /// Create the WPF visual for this object.
        /// </summary>
        /// <param name="parent">The canvas that is calling this method</param>
        /// <returns>The visual that can be displayed</returns>
        public UIElement CreateVisual(VirtualizingTilePanel2 parent) {
            lock (mLock) {
                if (null != mImage) {
                    return mImage;
                }

                mCts = new CancellationTokenSource();

                mImage = new Image();
                mImage.Stretch = Stretch.Uniform;
                mImage.Width = mTileSize.Width;
                mImage.Height = mTileSize.Height;
            }

            var uiThreadDispatcher = Dispatcher.CurrentDispatcher;

            Task.Factory.StartNew(new Action(() => {
                var token = mCts.Token;
                if (token.IsCancellationRequested) {
                    //Console.WriteLine("  Canceled 1 {0}", mContent.DisplayName);
                    return;
                }

                byte[] fileContent = null;
                using (var fs = new FileStream(mContent.Path, FileMode.Open, FileAccess.Read)) {
                    //Console.WriteLine("{0}", fs.Length);
                    var br = new BinaryReader(fs);
                    fileContent = br.ReadBytes((int)fs.Length);
                }

                if (token.IsCancellationRequested) {
                    //Console.WriteLine("  Canceled 2 {0}", mContent.DisplayName);
                    return;
                }

                BitmapImage bi = new BitmapImage();
                bi.BeginInit();
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.StreamSource = new MemoryStream(fileContent);
                bi.EndInit();
                bi.Freeze();

                if (token.IsCancellationRequested) {
                    //Console.WriteLine("  Canceled 3 {0}", mContent.DisplayName);
                    return;
                }

                if (bi != null) {
                    uiThreadDispatcher.Invoke(new Action(() => {
                        lock (mLock) {
                            if (mImage != null) {
                                mImage.Source = bi;
                                //Console.WriteLine("  Set image {0}", mContent.DisplayName);
                            }
                        }
                    }));
                }
            }), TaskCreationOptions.LongRunning);

            //Console.WriteLine("CreateVisual {0}", mContent.DisplayName);
            return mImage;
        }

        /// <summary>
        /// Dispose the WPF visual for this object.
        /// </summary>
        public void DisposeVisual() {
            lock (mLock) {
                if (mCts != null) {
                    mCts.Cancel();
                }
                mImage = null;
            }

            //Console.WriteLine("DisposeVisual {0}", mContent.DisplayName);
        }
    }
}
